﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using System.ComponentModel;
using System.Text;
using Stile.Patterns.Disposables;
using Stile.Patterns.SelfDescribingPredicates;
#endregion

namespace NJamb.Specifications.Simple
{
	public class RaisePropertyChangedAfterSpecification<TSource> : Disposable,
		IRaisePropertyChangedSpecification<TSource>
		where TSource : class, INotifyPropertyChanged
	{
		private Func<string> _actualPropertyNameGetter;
		private readonly string _expectedPropertyName;
		private Lazy<string> _lazySourceDescription;

		public RaisePropertyChangedAfterSpecification(Lazy<string> lazySourceDescription,
			string expectedPropertyName,
			Func<string> actualPropertyNameGetter)
		{
			_lazySourceDescription = lazySourceDescription;
			_expectedPropertyName = expectedPropertyName;
			_actualPropertyNameGetter = actualPropertyNameGetter;
		}

		public IEvaluation<string> Evaluate()
		{
			RequireNotAlreadyDisposed();

			string actualPropertyName = _actualPropertyNameGetter.Invoke();
			if (actualPropertyName == _expectedPropertyName || actualPropertyName == string.Empty)
			{
				return new Evaluation<string>(actualPropertyName);
			}

			return new Evaluation<string>(new Lazy<string>(() => Explain(actualPropertyName)), actualPropertyName);
		}

		protected override void Disposing()
		{
			_actualPropertyNameGetter = null;
			_lazySourceDescription = null;
		}

		private string Explain(string actualPropertyName)
		{
			var stringBuilder = new StringBuilder();
			stringBuilder.AppendFormat("expected {0} would notify of a change to its property {1}{2} but ",
				_lazySourceDescription.Value,
				_expectedPropertyName,
				Environment.NewLine);
			if (actualPropertyName == null)
			{
				stringBuilder.AppendFormat("it did not raise {0} at all.", typeof(INotifyPropertyChanged).Name);
			}
			else
			{
				stringBuilder.AppendFormat("it notified of a change to {0} instead.", actualPropertyName);
			}
			return stringBuilder.ToString();
		}
	}
}
